package cn.openea.perpartner.componet.util;

import cn.openea.perpartner.componet.web.vo.R;
import com.alibaba.fastjson.JSONObject;
import me.chanjar.weixin.mp.api.WxMpService;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
/**
 * @codeDesc: 消息发送http请求api的真实过程
 * @author: Mr.Yun
 * @QQ: 2034374624
 * @version: V1.0
 * @Created: 2021/04/29 21:13
 */
public class SendMsgApi {

    @Autowired
    private WxMpService wxMpService;
    private Logger logger = LoggerFactory.getLogger(SendMsgApi.class);

    /**
     * 发送消息功能
     *  这里有对一部分错误进行补发，当前只对 errcode=40001 或 errcode=40165 时需要将消息补发
     * @param msgobj 消息内容OBJ
     * @param msgType 消息类型 template 表示模板消息
     * @return
     * @throws Exception
     */
    public R sendMsg(JSONObject msgobj, String msgType) {
        String str = sendMsg(msgobj, msgType, false);
        // 如果消息发送是失败的，则再次强制获取 access_token 再尝试重发一次
        if(str.startsWith("{\"errcode\":40001,\"errmsg\":\"invalid credential, access_token is invalid or not latest")){
            str = this.sendMsg(msgobj, msgType, true);
        } else if(str.startsWith("{\"errcode\":40165,\"errmsg\":\"invalid weapp pagepath")){
            // 如果消息出现 40165 错误，发不出去时，可能需要使用 path 参数再一次重发，也许会成功，但如果不成功也将反回
            if(null == msgobj.getJSONObject("miniprogram")){
                return R.error(str);
            }
            JSONObject miniappdata = msgobj.getJSONObject("miniprogram");
            miniappdata.remove("pagepath");
            msgobj.put("miniprogram", miniappdata);
            str = sendMsg(msgobj, msgType, false);
        }

        // 在这里进行封装结果
        R r = R.ok();
        try {
            JSONObject jsonObject = JSONObject.parseObject(str);
            if(!"0".equals(jsonObject.getString("errcode"))) {
                r = R.error(jsonObject.getString("errmsg"));
            }
            String errmsg = jsonObject.getString("errmsg");
            r.setMsg(errmsg);
        } catch (Exception e) {
            r = R.error(str);
        }
        return r;
    }

    /**
     * 发送消息功能
     * @param msgobj 消息内容OBJ
     * @param msgType 消息类型 template 表示模板消息
     * @param forceRefresh 是否强制获取access_token，值为true表示强制获取
     * @return
     * @throws Exception
     */
    private String sendMsg(JSONObject msgobj, String msgType, boolean forceRefresh) {
        String str = "";
        try {
            // 普通获取的Token，这里的token信息可能是5-20分钟内有效，具体时间是随机值，所以很坑
            String access_token = wxMpService.getAccessToken(forceRefresh);
            logger.debug("access_token ===> " + access_token);
            MsgTypeHandler msgTypeHandler = new MsgTypeHandler(msgType);
            String apiurl = msgTypeHandler.getMsgApi();
            logger.debug("apiurl ===> " + apiurl);
            str = dohttpPost(apiurl.replace("ACCESS_TOKEN", access_token), msgobj.toJSONString());
        } catch (Exception e) {
            e.printStackTrace();
            logger.debug("post.Exception ===> " + Arrays.toString(e.getStackTrace()));
        }
        logger.debug("post.code ===> " + str);
        return str;
    }

    /**
     * 调用httpPost请求并将结果包装成String反回
     * @param url 请求的地址
     * @param data 请求时附带的参数
     * @return
     * @throws Exception
     */
    public String dohttpPost(String url, String data) throws Exception {
        String str = "";
        if(url.indexOf("ACCESS_TOKEN") != -1) {
            String access_token = wxMpService.getAccessToken();
            url = url.replace("ACCESS_TOKEN", access_token);
            logger.debug("dohttpPost.replaceUrl.ACCESS_TOKEN ===> " + url);
        }
        HttpPost httpPost = new HttpPost(url);
        CloseableHttpClient httpClient = HttpClients.custom().build();
        httpPost.setEntity(new StringEntity(data,"UTF-8"));
        CloseableHttpResponse response = httpClient.execute(httpPost);
        HttpEntity rsEntity = response.getEntity();
        if(rsEntity != null){
            InputStream instream = rsEntity.getContent();
            str = this.streamToString(instream,"UTF-8");
        }
        return str;
    }

    /**
     * 把InputStream转换为字符串
     * @param is InputStream对像
     * @param charset 如：UTF-8等
     * @return 从流中得到的字符串
     * @throws Exception 输入流异常
     */
    private String streamToString(InputStream is, String charset) throws Exception {
        BufferedReader reader = new BufferedReader(new InputStreamReader(is, charset));
        StringBuilder sb = new StringBuilder();

        String line = null;
        try {
            while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return sb.toString();
    }
}
